#include "SimulatedAnnealing.hpp"
#include <cstdlib>
#include <cmath>


void    SimulatedAnnealing::execute() EXC_THROWER()
{
    EXC_RETHROW_BEGIN()
    {
        unsigned    iteration = 0;
        
        // initialisation
        saTemperature = 9999999.;
        saSol.complete();
        saNSol = saSol;
        saRecord = saSol;
        saSol.eval(&saSolE);
        saNSolE = saSolE;
        saRecordE = saSolE;
        
        // 
        for (;; iteration++)
        {
            saRand = ((rand() * 1.0) / RAND_MAX);
             
            this->build_neighbor();
            saNSol.eval(&saNSolE);
            
            if (saNSolE < saRecordE)
            {
                saRecord = saNSol;
                saRecordE = saNSolE;
                
                std::cout << saRecord.toString() << std::endl;
                std::cout << saRecordE.toString() << std::endl;
                
                std::cout << "record @" << iteration << std::endl;
            }
                       
            if (saNSolE <= saSolE)
            {
                //std::cout << "amel @" << iteration << std::endl;
                saSol = saNSol;
                saSolE = saNSolE;
            }
            else if (saRand <= (exp(-(((saNSolE.getHD() - saSolE.getHD()) / 1.) / saTemperature))))
            {
                //std::cout << "wore @" << iteration << std::endl;
                //this->split();
                saSol = saNSol;
                saSolE = saNSolE;
            }
            
            saTemperature *= 0.9999;
        }
    }
    EXC_RETHROW_END()
}


void   SimulatedAnnealing::build_neighbor()
{
    EXC_RETHROW_BEGIN()
    {
        unsigned    i = 0;
        unsigned    r1;
        unsigned    r2;
        unsigned    rnd = (rand() % (saSolE.seNTournees + 1));
        unsigned    n = rand() % 10;
        
        saNSol = saSol;
        
        for (i = 0 ; i < n ; i++)
        {
            do
            {
                r1 = saNSol.getFilledRandomTournee();
                if (rnd == 0)
                {
                    r2 = saNSol.getEmptyRandomTournee();
                }
                else
                    r2 = saNSol.getFilledRandomTournee();
            }   while (r1 == r2);
            
            localVND3(saNSol[r1], saNSol[r2]);
            saNSol.validateTournee(r1);
            saNSol.validateTournee(r2);
        }
    }
    EXC_RETHROW_END()
}


